﻿using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Collections.Generic;
using UIDesigner.Designers;
using SharedClasses;
using System.ComponentModel.Design;
using DDW;
using AFSharedLibrary;
using UIDesigner.FieldHandlers;
using System.IO;
using System.Reflection;
using UIDesigner.FieldHandlers.Bases;
using UIDesigner.Editors;
using UIDesigner.SurfaceProperties;

namespace UIDesigner.DesignContainers.Bases
{
    [Designer(typeof(Design.ObjectUIDesigner))]
    public abstract class BaseObjectControlContainer : ScrollableControl, IContainerControl, IBaseObjectControl
    {
        private Dictionary<string, ConstructedTypeNode> m_rgRequestedTypes;
        private Dictionary<string, CompilationUnitNode> m_rgCompiledFiles; 
        protected Control m_ctrlActive;
        protected bool m_bFirstPaint;
        protected AFDesignerHost m_objHost;
        protected ISelectionService m_objSelectionService;
        protected bool m_bSelected = false;
        protected bool m_bUseErrorProvider = true;
        protected string m_strBusObjectsLocation;
        protected StatusBar m_ctrlStatusBar;
        protected abstract void OnLoad(object sender);
        public abstract void ApplySurfaceProperties(SurfacePropertiesBase objSelected);
        public abstract Construct BusinessObject { get; }
        public abstract void HandleSurfaceProperties(DynamicEnumType objDynamicEnumType);
        public abstract void RemoveTemplatedControls();
        public abstract void RemoveSurfaceControls();
        public abstract void OnFlush();
        public event BaseObjectControlHandlers.PromoteOptionsPanelHandler PromoteOptionsPanel;

        protected void RaisePromoteOptionsPanel(Panel ctrlOptionsPanel)
        {
            PromoteOptionsPanel(this, ctrlOptionsPanel);
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool UseErrorProvider
        {
            get 
            { 
                return m_bUseErrorProvider; 
            }
            
            set 
            { 
                m_bUseErrorProvider = value; 
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public StatusBar StatusBar
        {
            get 
            { 
                return m_ctrlStatusBar; 
            }
            
            set 
            { 
                m_ctrlStatusBar = value; 
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string BusObjectsLocation
        {
            get
            {
                return m_strBusObjectsLocation;
            }

            set 
            { 
                m_strBusObjectsLocation = value; 
            }
        }

        public BaseObjectControlContainer()
        {
            this.AutoScroll = true;

            BaseFieldHandler.RequestType += new Handlers.RequestTypeHandler(RequestType);
            this.Paint += new PaintEventHandler(OnPaint);
        }

        protected IServiceContainer ServiceContainer
        {
            get
            {
                return (IServiceContainer)m_objHost;
            }
        }

        protected void OnPaint(object sender, PaintEventArgs e)
        {
            if (!m_bFirstPaint)
            {
                if (this.Site != null)
                {
                    m_objHost = (AFDesignerHost)this.Site.Container;
                    m_objSelectionService = (ISelectionService)this.ServiceContainer.GetService(typeof(ISelectionService));

                    m_objSelectionService.SelectionChanged += new EventHandler(SelectionChanged);
                }

                m_bFirstPaint = true;
                OnLoad(sender);
            }
        }

        protected int GetPaddingWidth(TableLayoutPanel ctrlInnerPanel)
        {
            int nWidth = ctrlInnerPanel.Margin.Left + ctrlInnerPanel.Margin.Right;

            nWidth += ctrlInnerPanel.Padding.Left + ctrlInnerPanel.Padding.Right;

            foreach (Control ctrl in ctrlInnerPanel.Controls)
            {
                nWidth += ctrl.Margin.Left + ctrl.Margin.Right;
                nWidth += ctrl.Padding.Left + ctrl.Padding.Right;
            }

            return nWidth;
        }

        protected int GetPaddingHeight(TableLayoutPanel ctrlInnerPanel)
        {
            int nHeight = ctrlInnerPanel.Margin.Top + ctrlInnerPanel.Margin.Bottom;

            nHeight += ctrlInnerPanel.Padding.Top + ctrlInnerPanel.Padding.Bottom;

            foreach (Control ctrl in ctrlInnerPanel.Controls)
            {
                nHeight += ctrl.Margin.Top + ctrl.Margin.Bottom;

                if (ctrlInnerPanel.RowCount == 1)
                {
                    break;
                }
            }

            return nHeight;
        }

        protected void SelectionChanged(object sender, EventArgs e)
        {
            m_bSelected = false;

            foreach (IComponent objComponent in m_objSelectionService.GetSelectedComponents())
            {
                if (objComponent == this)
                {
                    m_bSelected = true;
                }
            }

            this.Refresh();
        }

        protected bool IsBrowsable(MemberNode objProperty)
        {
            foreach (AttributeNode objAttr in objProperty.Attributes)
            {
                if (objAttr.Name.GenericIdentifier == "Browsable")
                {
                    BooleanPrimitive objBool = (BooleanPrimitive) objAttr.Arguments[0].Expression;

                    if (objBool.Value == false)
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        protected bool IsBusObjectMember(MemberNode objProperty)
        {
            Type objType = typeof(IBusinessObject);

            foreach (MemberInfo objMember in objType.GetMembers())
            {
                string strName = objMember.Name;

                if (strName.StartsWith("get_"))
                {
                    strName = strName.Substring("get_".Length);
                }
                else if (strName.StartsWith("set_"))
                {
                    strName = strName.Substring("set_".Length);
                }

                if (strName == objProperty.Names[0].GenericIdentifier)
                {
                    return true;
                }
            }

            return false;
        }
        protected void RequestType(DirectoryInfo objDir, string strName, out ConstructedTypeNode objTypeNodeOut)
        {
            Type objType = Type.GetType("System." + strName, false, true); 

            objTypeNodeOut = null;

            if (objType != null)
            {
                return;
            }

            if (m_rgRequestedTypes == null)
            {
                m_rgRequestedTypes = new Dictionary<string, ConstructedTypeNode>();
            }
            else
            {
                if (m_rgRequestedTypes.ContainsKey(strName))
                {
                    objTypeNodeOut = m_rgRequestedTypes[strName];
                    return;
                }
            }

            foreach (FileInfo objFile in objDir.GetFiles())
            {
                if (objFile.Name.EndsWith(".cs"))
                {
                    CompilationUnitNode objNode;

                    if (m_rgCompiledFiles == null)
                    {
                        m_rgCompiledFiles = new Dictionary<string, CompilationUnitNode>();
                        objNode = CSharpParser.Parse(objFile.FullName);

                        m_rgCompiledFiles.Add(objFile.FullName, objNode);
                    }
                    else
                    {
                        if (m_rgCompiledFiles.ContainsKey(objFile.FullName))
                        {
                            objNode = m_rgCompiledFiles[objFile.FullName];
                        }
                        else
                        {
                            objNode = CSharpParser.Parse(objFile.FullName);
                            m_rgCompiledFiles.Add(objFile.FullName, objNode);
                        }
                    }

                    foreach (NamespaceNode objNamespace in objNode.Namespaces)
                    {
                        foreach (ClassNode objClass in objNamespace.Classes)
                        {
                            if (objClass.Name.Identifier == strName)
                            {
                                objTypeNodeOut = objClass;
                                m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                                return;
                            }
                        }

                        foreach (StructNode objStruct in objNamespace.Structs)
                        {
                            if (objStruct.Name.Identifier == strName)
                            {
                                objTypeNodeOut = objStruct;
                                m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                                return;
                            }
                        }

                        foreach (InterfaceNode objInterface in objNamespace.Interfaces)
                        {
                            if (objInterface.Name.Identifier == strName)
                            {
                                objTypeNodeOut = objInterface;
                                m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                                return;
                            }
                        }

                        foreach (EnumNode objEnum in objNamespace.Enums)
                        {
                            if (objEnum.Name.Identifier == strName)
                            {
                                objTypeNodeOut = objEnum;
                                m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                                return;
                            }
                        }
                    }

                    foreach (ClassNode objClass in objNode.DefaultNamespace.Classes)
                    {
                        if (objClass.Name.Identifier == strName)
                        {
                            objTypeNodeOut = objClass;
                            m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                            return;
                        }
                    }

                    foreach (StructNode objStruct in objNode.DefaultNamespace.Structs)
                    {
                        if (objStruct.Name.Identifier == strName)
                        {
                            objTypeNodeOut = objStruct;
                            m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                            return;
                        }
                    }

                    foreach (InterfaceNode objInterface in objNode.DefaultNamespace.Interfaces)
                    {
                        if (objInterface.Name.Identifier == strName)
                        {
                            objTypeNodeOut = objInterface;
                            m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                            return;
                        }
                    }

                    foreach (EnumNode objEnum in objNode.DefaultNamespace.Enums)
                    {
                        if (objEnum.Name.Identifier == strName)
                        {
                            objTypeNodeOut = objEnum;
                            m_rgRequestedTypes.Add(strName, objTypeNodeOut);

                            return;
                        }
                    }
                }
            }

            foreach (DirectoryInfo objSubDir in objDir.GetDirectories())
            {
                RequestType(objSubDir, strName, out objTypeNodeOut);

                if (objTypeNodeOut != null)
                {
                    return;
                }
            }
        }

        protected void RequestType(string strName, out ConstructedTypeNode objTypeNodeOut)
        {
            DirectoryInfo objDir = new DirectoryInfo(m_strBusObjectsLocation);

            RequestType(objDir, strName, out objTypeNodeOut);
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Control ActiveControl
        {
            get
            {
                return m_ctrlActive;
            }

            set
            {
                // Make sure the control is a member of the ControlCollection.
                if (this.Controls.Contains(value))
                {
                    m_ctrlActive = value;
                }
            }
        }

        // Add implementations to the IContainerControl.ActivateControl(Control) method.
        public bool ActivateControl(Control active)
        {
            if (this.Controls.Contains(active))
            {
                // Select the control and scroll the control into view if needed.
                active.Select();
                this.ScrollControlIntoView(active);
                this.m_ctrlActive = active;
                return true;
            }
            return false;
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == (int)WindowsAPI.WindowsMessage.WM_PAINT)
            {
                if (this.DesignMode)
                {
                    if (!m_bSelected)
                    {
                        int hwnd = this.Handle.ToInt32();
                        WindowsAPI.RECT rc = new WindowsAPI.RECT();
                        int hdc = WindowsAPI.GetDC(hwnd);
                        int hPen = WindowsAPI.CreatePen(WindowsAPI.PenStyles.PS_ALTERNATE, 1, 0);
                        int hOldBrush;
                        int hOldPen;

                        hOldPen = WindowsAPI.SelectObject(hdc, hPen);
                        hOldBrush = WindowsAPI.SelectObject(hdc, WindowsAPI.GetStockObject(WindowsAPI.StockObjects.NULL_BRUSH));

                        WindowsAPI.GetClientRect(hwnd, ref rc);

                        WindowsAPI.Rectangle(hdc, rc.Left, rc.Top, rc.Right, rc.Bottom);

                        WindowsAPI.SelectObject(hdc, hOldPen);
                        WindowsAPI.SelectObject(hdc, hOldBrush);

                        WindowsAPI.ReleaseDC(hwnd, hdc);
                    }
                }
            }
        }

        public Control PropertyGridView
        {
            get
            {
                PropertyGrid ctrlGrid = (PropertyGrid)((IServiceProvider)m_objHost).GetService(typeof(PropertyGrid));

                foreach (Control ctrl in ((Control)ctrlGrid).Controls)
                {
                    if (ctrl.GetType().Name == "PropertyGridView")
                    {
                        return ctrl;
                    }
                }

                return null;
            }
        }
    }
}
